﻿using System;
using System.Collections.Generic;
using NHibernate;
using Neturion.Dados;
using Neturion.IRepositorios;
using NHibernate.Criterion;
using NHibernate.SqlCommand;

namespace Neturion.Repositorios
{
    public class RepositorioTitulo : IRepositorioTitulo
    {
        public Titulo Inserir(Titulo titulo)
        {
            GerenciadorBDConfigs.Instance.SessaoAtual().Save(titulo);
            return titulo;
        }

        public Titulo Atualizar(Titulo titulo)
        {
            Titulo tmpTitulo = ObterPorId(titulo.MovimentoId);
            // Atribuicao dos valores do objeto da memoria para o objeto obtido no banco de dados
            tmpTitulo.DataCadastro = titulo.DataCadastro;
            tmpTitulo.DataEmissao = titulo.DataEmissao;
            tmpTitulo.DataExtorno = titulo.DataExtorno;
            tmpTitulo.DataQuitado = titulo.DataQuitado;
            tmpTitulo.DataVencimento = titulo.DataVencimento;
            tmpTitulo.Desconto = titulo.Desconto;
            tmpTitulo.DescontoCofins = titulo.DescontoCofins;
            tmpTitulo.DescontoCssl = titulo.DescontoCssl;
            tmpTitulo.DescontoInss = titulo.DescontoInss;
            tmpTitulo.DescontoIr = titulo.DescontoIr;
            tmpTitulo.DescontoIss = titulo.DescontoIss;
            tmpTitulo.Descricao = titulo.Descricao;
            tmpTitulo.Documento = titulo.Documento;
            tmpTitulo.Historico = titulo.Historico;
            tmpTitulo.JurosTaxas = titulo.JurosTaxas;
            tmpTitulo.EnumSituacaoMovimento = titulo.EnumSituacaoMovimento;
            tmpTitulo.EnumTipoMovimentoFinanceiro = titulo.EnumTipoMovimentoFinanceiro;
            tmpTitulo.Multa = titulo.Multa;
            tmpTitulo.Valor = titulo.Valor;
            tmpTitulo.ValidadePagamento = titulo.ValidadePagamento;
            tmpTitulo.Usuario = titulo.Usuario;
            tmpTitulo.NossoNumero = titulo.NossoNumero;
            tmpTitulo.Ipte = titulo.Ipte;
            tmpTitulo.RegistroRetorno = titulo.RegistroRetorno;

            tmpTitulo.ListaPagamentos.Clear();
            foreach (Pagamento pagamento in titulo.ListaPagamentos)
            {
                tmpTitulo.AdicionarPagamento(pagamento);
            }

            GerenciadorBDConfigs.Instance.SessaoAtual().Merge(tmpTitulo);
            return tmpTitulo;
        }

        public void Excluir(Titulo titulo)
        {
            GerenciadorBDConfigs.Instance.SessaoAtual().Delete(titulo);
        }

        public IList<Titulo> ObterTodos()
        {
            ICriteria criteria = GerenciadorBDConfigs.Instance.SessaoAtual().CreateCriteria(typeof(Titulo));
            return criteria.List<Titulo>() as List<Titulo>;
        }

        public IList<Titulo> ObterTodos(int inicio, int quantidade, int quantidadeMinima, 
            string ipte,
            string nossoNumero,
            EnumTipoMovimentoFinanceiro enumTipoMovimentoFinanceiro, 
            string documento, 
            long numeroMovimento, 
            long numeroTitulo, 
            string descricao, 
            EnumSituacaoMovimento enumSituacaoMovimento, 
            bool parcelado, 
            Pessoa credorDevedor, 
            Setor setor, 
            FonteGeradora fonteGeradora, 
            ContaContabil contaContabil, 
            DateTime? emissaoDe, 
            DateTime? emissaoAte, 
            DateTime? vencimentoDe, 
            DateTime? vencimentoAte, 
            DateTime? aceitoDe, 
            DateTime? aceitoAte, 
            DateTime? quitadoDe, 
            DateTime? quitadoAte, 
            DateTime? estornadoDe, 
            DateTime? estornadoAte, 
            decimal valorDe, 
            decimal valorAte, 
            FormaPagamento formaPagamento, 
            TipoFormaPagamento tipoFormaPagamento)
        {
            if (quantidade.Equals(0))
            {
                quantidade = quantidadeMinima;
            }

            ICriteria criteria = GerenciadorBDConfigs.Instance.SessaoAtual()
                .CreateCriteria(typeof(Titulo))
                .Add(Restrictions.Eq("EnumTipoMovimentoFinanceiro", enumTipoMovimentoFinanceiro))
                .CreateAlias("MovimentoFinanceiro", "MovimentoFinanceiroDoTitulo")
                .SetFirstResult(inicio).SetMaxResults(quantidade);

            if (!String.IsNullOrEmpty(ipte))
            {
                criteria.Add(Restrictions.Eq("Ipte", ipte));
            }

            if (!String.IsNullOrEmpty(nossoNumero))
            {
                criteria.Add(Restrictions.Eq("NossoNumero", nossoNumero));
            }

            if (!String.IsNullOrEmpty(documento))
            {
                criteria.Add(Restrictions.Eq("Documento", documento));
            }

            if (numeroMovimento > 0)
            {
                criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.MovimentoId", numeroMovimento));
            }

            if (numeroTitulo > 0)
            {
                criteria.Add(Restrictions.Eq("MovimentoId", numeroTitulo));
            }

            if (!String.IsNullOrEmpty(descricao))
            {
                criteria.Add(Restrictions.Like("Descricao", descricao, MatchMode.Anywhere));
            }

            if (enumSituacaoMovimento != EnumSituacaoMovimento.Inserindo)
            {
                criteria.Add(Restrictions.Eq("EnumSituacaoMovimento", enumSituacaoMovimento));
            }

            //Parcelado
            criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.Parcelado", parcelado));

            if (credorDevedor != null)
            {
                criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.PessoaCredorDevedor", credorDevedor));
            }

            if (setor != null)
            {
                criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.Setor", setor));
            }

            if (setor != null)
            {
                criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.Setor", setor));
            }

            if (fonteGeradora != null)
            {
                criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.FonteGeradora", fonteGeradora));
            }

            if (contaContabil != null)
            {
                criteria.Add(Restrictions.Eq("MovimentoFinanceiroDoTitulo.ContaContabil", contaContabil));
            }

            if (emissaoDe.HasValue)
            {
                criteria.Add(emissaoAte.HasValue
                                 ? Restrictions.Between("DataEmissao", emissaoDe.GetValueOrDefault().Date,
                                                        emissaoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataEmissao", emissaoDe.GetValueOrDefault().Date));
            }

            if (vencimentoDe.HasValue)
            {
                criteria.Add(vencimentoAte.HasValue
                                 ? Restrictions.Between("DataVencimento", vencimentoDe.GetValueOrDefault().Date,
                                                        vencimentoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataVencimento", vencimentoDe.GetValueOrDefault().Date));
            }

            if (aceitoDe.HasValue)
            {
                criteria.Add(aceitoAte.HasValue
                                 ? Restrictions.Between("MovimentoFinanceiroDoTitulo.DataAceitacao",
                                                        aceitoDe.GetValueOrDefault().Date,
                                                        aceitoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("MovimentoFinanceiroDoTitulo.DataAceitacao",
                                                   aceitoDe.GetValueOrDefault().Date));
            }

            if (quitadoDe.HasValue)
            {
                criteria.Add(estornadoAte.HasValue
                                 ? Restrictions.Between("DataQuitado", quitadoDe.GetValueOrDefault().Date,
                                                        estornadoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataQuitado", quitadoDe.GetValueOrDefault().Date));
            }

            if (estornadoDe.HasValue)
            {
                criteria.Add(quitadoAte.HasValue
                                 ? Restrictions.Between("DataExtorno", estornadoDe.GetValueOrDefault().Date,
                                                        quitadoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataExtorno", estornadoDe.GetValueOrDefault().Date));
            }

            if (valorDe > 0)
            {
                criteria.Add(valorAte > valorDe
                                 ? Restrictions.Between("Valor", valorDe, valorAte)
                                 : Restrictions.Eq("Valor", valorDe));
            }

            if (formaPagamento != null)
            {
                criteria.CreateAlias("ListaPagamentos", "Pagamentos")
                    .Add(Restrictions.Or(
                    Restrictions.Eq("MovimentoFinanceiroDoTitulo.FormaPagamento", formaPagamento),
                    Restrictions.Eq("Pagamentos.FormaPagamento", formaPagamento)));
            }
            else
            {
                if (tipoFormaPagamento != null)
                {
                    criteria.CreateAlias("ListaPagamentos", "Pagamentos")
                   .CreateAlias("MovimentoFinanceiroDoTitulo.FormaPagamento", "FormaPagamentoDoMovimentoFinanceiroDoTitulo")
                   .CreateAlias("Pagamentos.FormaPagamento", "FormaPagamentoDoPagamento")
                   .Add(Restrictions.Or(
                   Restrictions.Eq("FormaPagamentoDoMovimentoFinanceiroDoTitulo.TipoFormaPagamento", tipoFormaPagamento),
                   Restrictions.Eq("FormaPagamentoDoPagamento.TipoFormaPagamento", tipoFormaPagamento)));
                }
            }

            return criteria.List<Titulo>() as List<Titulo>;
        }

        public Titulo ObterPorId(long id)
        {
            return GerenciadorBDConfigs.Instance.SessaoAtual().Get<Titulo>(id);
        }
    }
}